﻿#region Using Directives
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

#endregion

namespace DarkMatter.Chat
{
    public class XmlMessageEncoder : IMessageEncoder
    {
        private readonly Encoding _encoding;

        public XmlMessageEncoder(Encoding encoding)
        {
            _encoding = encoding;
        }

        public byte[] Encode(Message message)
        {
            string messageXml = ConvertMessageToXml(message);

            return _encoding.GetBytes(messageXml);
        }

        public Message Decode(byte[] bytes)
        {
            string messageXml = _encoding.GetString(bytes);

            return ConvertXmlToMessage(messageXml);
        }

        private static Message ConvertXmlToMessage(string messageXml)
        {
            Message message = null;
            TextReader r = new StringReader(messageXml);
            XmlTextReader reader = new XmlTextReader(r);

            string messageType = null;
            string nodeId = null;
            string userName = null;
            byte[] payload = new byte[0];

            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    switch (reader.Name)
                    {
                        case "Message":
                            reader.MoveToAttribute("type");
                            messageType = reader.ReadContentAsString();
                            break;
                        case "Source":
                            reader.MoveToAttribute("nodeId");
                            nodeId = reader.ReadContentAsString();
                            reader.MoveToAttribute("userName");
                            userName = reader.ReadContentAsString();
                            break;
                        case "Payload":
                            reader.MoveToContent();
                            byte[] tempPayload = new byte[1000];
                            int bytesRead = reader.ReadElementContentAsBinHex(tempPayload, 0, 1000);
                            payload = new byte[bytesRead];
                            Array.Copy(tempPayload, payload, bytesRead);
                            break;
                    }
                        
                }
            }

            message = new Message(new ChatUser(userName, nodeId), messageType, payload);

            return message;
        }

        private static string ConvertMessageToXml(Message message)
        {
            TextWriter w = new StringWriter();
            XmlTextWriter xmlWriter = new XmlTextWriter(w);

            xmlWriter.WriteStartDocument();

            xmlWriter.WriteStartElement("Message");

            xmlWriter.WriteStartAttribute("type");
            xmlWriter.WriteString(message.MessageType);
            xmlWriter.WriteEndAttribute();

            xmlWriter.WriteStartElement("Source");
            xmlWriter.WriteStartAttribute("nodeId");
            xmlWriter.WriteString(message.Source.NodeId);
            xmlWriter.WriteEndAttribute();
            xmlWriter.WriteStartAttribute("userName");
            xmlWriter.WriteString(message.Source.UserName);
            xmlWriter.WriteEndAttribute();
            xmlWriter.WriteEndElement();

            xmlWriter.WriteStartElement("Payload");
            xmlWriter.WriteBinHex(message.Payload, 0, message.Payload.Length);
            xmlWriter.WriteEndElement();

            xmlWriter.WriteEndElement();

            xmlWriter.WriteEndDocument();

            return w.ToString();
        }
    }
}
